import {
  barMargin,
  responsiveUnitWidth,
  responsivePersonColumnWidth,
  responsiveBarHeight,
  responsiveConfig,
} from '../config';
import { GanttTable } from '../components/gantt-table';
import { getUniquePersons } from '../utils/helper';
import { useScheduleStore } from '../../stores/schedule';
import { watch } from 'vue';
import { useCalendarStore } from '../../stores/calendar';

interface DateRange {
  start: string;
  end: string;
}

export class ScheduleRenderer {
  // ZRender实例
  private zr: any;
  // 人员排班数据
  private schedules: PersonSchedule[];
  // 滚动位置
  private scrollState: ScrollState;
  // 日期范围
  private dateRange: DateRange;
  // 是否是第一次处理
  private isFirstFlag: boolean;
  // 上一次处理移动
  private lastHandleMove: any;
  // 当前组
  private currentGroup: any;
  // 排班store
  private scheduleStore: any;
  // 数据监听器
  private unwatchSchedules: (() => void) | null = null;
  // 窗口大小变化监听器
  private resizeObserver: ResizeObserver | null = null;
  // 防抖定时器
  private resizeTimeout: number | null = null;
  // 甘特表格组件
  private ganttTable: GanttTable | null = null;

  constructor(zr: any, schedules: PersonSchedule[], scrollState: ScrollState, dateRange: DateRange) {
    this.zr = zr;
    this.schedules = schedules;
    this.scrollState = scrollState;
    this.dateRange = dateRange;
    this.isFirstFlag = true;
    this.lastHandleMove = null;
    this.currentGroup = null;
    this.scheduleStore = null;
    this.resizeObserver = null;
    this.resizeTimeout = null;

    // 添加滚动和键盘事件监听
    this.setupScrollAndKeyboardEvents();

    // 添加响应式宽度变化监听
    this.setupResizeObserver();

    // 初始化甘特表格组件
    this.initializeGanttTable();
  }

  /**
   * 初始化甘特表格组件
   */
  private initializeGanttTable() {
    const chartState = this.calculateChartState(this.scrollState.lastScrollX, this.scrollState.lastScrollY);
    this.ganttTable = new GanttTable(this.zr, this.schedules, chartState);
    this.ganttTable.setRowReorderCallback(this.handleRowReorder);
  }

  /**
   * 更新日期范围
   */
  updateDateRange(dateRange: DateRange) {
    this.dateRange = dateRange;
  }

  /**
   * 计算基于store日期范围的时间配置
   */
  private getTimeConfig() {
    const calendarStore = useCalendarStore();
    const startDate = new Date(calendarStore.dateRange.start);
    const endDate = new Date(calendarStore.dateRange.end);

    // 计算总天数（包含开始和结束日期）
    const totalDays = Math.floor((+endDate - +startDate) / (60 * 60 * 24 * 1000)) + 1;

    // 从开始日期到今天的天数偏移量
    const todayOffset = Math.floor((+new Date() - +startDate) / (60 * 60 * 24 * 1000));

    return {
      startDate,
      endDate,
      totalDays,
      todayOffset,
    };
  }

  /**
   * 设置滚动和键盘事件
   */
  setupScrollAndKeyboardEvents() {
    const container = this.zr.dom;

    // 鼠标滚轮事件
    container.addEventListener('wheel', (e: WheelEvent) => {
      e.preventDefault();

      // 水平滚动（Shift + 滚轮 或者 touchpad水平滚动）
      if (e.shiftKey || Math.abs(e.deltaX) > Math.abs(e.deltaY)) {
        this.scrollState.lastScrollX += e.deltaX * 2;
      } else {
        // 垂直滚动
        this.scrollState.lastScrollY += e.deltaY;
      }

      // 限制滚动范围在时间范围内
      const canvasWidth = this.zr.getWidth();
      const canvasHeight = this.zr.getHeight();
      const { totalDays } = this.getTimeConfig();
      const responsiveConfig = this.getResponsiveConfig();
      const maxScrollX = Math.max(0, totalDays * responsiveConfig.unitWidth - canvasWidth + responsiveConfig.personColumnWidth);
      this.scrollState.lastScrollX = Math.max(0, Math.min(this.scrollState.lastScrollX, maxScrollX));
      // 计算最大可滚动高度
      const uniquePersons = getUniquePersons(this.schedules);
      const contentHeight = uniquePersons.length * (responsiveConfig.barHeight + barMargin);
      const maxScrollY = Math.max(0, contentHeight - canvasHeight);
      this.scrollState.lastScrollY = Math.max(0, Math.min(this.scrollState.lastScrollY, maxScrollY));

      this.draw(true, this.scrollState.lastScrollX, this.scrollState.lastScrollY);
    });

    // 键盘事件
    document.addEventListener('keydown', (e: KeyboardEvent) => {
      // 确保焦点在容器上时才响应
      if (document.activeElement === container || container.contains(document.activeElement)) {
        const responsiveConfig = this.getResponsiveConfig();
        const scrollStep = responsiveConfig.unitWidth;
        const verticalScrollStep = responsiveConfig.barHeight + barMargin;

        let needRedraw = false;

        switch (e.key) {
          case 'ArrowLeft':
            e.preventDefault();
            this.scrollState.lastScrollX -= scrollStep;
            needRedraw = true;
            break;
          case 'ArrowRight':
            e.preventDefault();
            this.scrollState.lastScrollX += scrollStep;
            needRedraw = true;
            break;
          case 'ArrowUp':
            e.preventDefault();
            this.scrollState.lastScrollY -= verticalScrollStep;
            needRedraw = true;
            break;
          case 'ArrowDown':
            e.preventDefault();
            this.scrollState.lastScrollY += verticalScrollStep;
            needRedraw = true;
            break;
          case 'Home':
            e.preventDefault();
            this.scrollState.lastScrollX = 0;
            this.scrollState.lastScrollY = 0;
            needRedraw = true;
            break;
          // case 'End':
          //   e.preventDefault();
          //   // 跳转到最后有排班的时间
          //   const lastShift = this.findLastShift();
          //   if (lastShift) {
          //     this.scrollState.lastScrollX = (lastShift.start + lastShift.duration - 3) * unitWidth;
          //   }
          //   needRedraw = true;
          //   break;
        }

        if (needRedraw) {
          // 限制滚动范围在时间范围内
          const canvasWidth = this.zr.getWidth();
          const canvasHeight = this.zr.getHeight();
          const { totalDays } = this.getTimeConfig();
          const responsiveConfig = this.getResponsiveConfig();
          const maxScrollX = Math.max(0, totalDays * responsiveConfig.unitWidth - canvasWidth + responsiveConfig.personColumnWidth);
          this.scrollState.lastScrollX = Math.max(0, Math.min(this.scrollState.lastScrollX, maxScrollX));
          // 计算最大可滚动高度
          const uniquePersons = getUniquePersons(this.schedules);
          const contentHeight = uniquePersons.length * (responsiveConfig.barHeight + barMargin);
          const maxScrollY = Math.max(0, contentHeight - canvasHeight);
          this.scrollState.lastScrollY = Math.max(0, Math.min(this.scrollState.lastScrollY, maxScrollY));

          this.draw(true, this.scrollState.lastScrollX, this.scrollState.lastScrollY);
        }
      }
    });

    // 使容器可以获得焦点
    container.tabIndex = 0;
    container.style.outline = 'none';
  }

  /**
   * 设置响应式宽度变化监听
   */
  private setupResizeObserver() {
    // 使用 ResizeObserver 监听容器大小变化
    if (window.ResizeObserver) {
      this.resizeObserver = new ResizeObserver(_entries => {
        // 防抖处理，避免频繁重绘
        if (this.resizeTimeout) {
          clearTimeout(this.resizeTimeout);
        }

        this.resizeTimeout = window.setTimeout(() => {
          this.handleResize();
        }, 100);
      });

      // 监听 ZRender 容器
      if (this.zr && this.zr.dom) {
        this.resizeObserver.observe(this.zr.dom);
      }
    } else {
      // 降级方案：使用 window resize 事件
      window.addEventListener('resize', () => {
        if (this.resizeTimeout) {
          clearTimeout(this.resizeTimeout);
        }

        this.resizeTimeout = window.setTimeout(() => {
          this.handleResize();
        }, 100);
      });
    }
  }

  /**
   * 处理容器大小变化
   */
  private handleResize() {
    // 重新设置 ZRender 大小
    if (this.zr) {
      this.zr.resize();
    }

    // 重新计算滚动范围并调整滚动位置
    this.adjustScrollPositionAfterResize();

    // 重新绘制
    this.draw(true, this.scrollState.lastScrollX, this.scrollState.lastScrollY);
  }

  /**
   * 获取响应式配置
   */
  private getResponsiveConfig() {
    const canvasWidth = this.zr.getWidth();
    const canvasHeight = this.zr.getHeight();
    const { totalDays } = this.getTimeConfig();
    const uniquePersons = getUniquePersons(this.schedules);

    // 获取当前断点
    const breakpoint = responsiveConfig.getBreakpoint(canvasWidth);
    const breakpointConfig = responsiveConfig.getConfigByBreakpoint(breakpoint);

    // 动态计算配置
    const dynamicUnitWidth = responsiveUnitWidth.calculate(canvasWidth, breakpointConfig.personColumnWidth, totalDays);
    const dynamicPersonColumnWidth = responsivePersonColumnWidth.calculate(canvasWidth);
    const dynamicBarHeight = responsiveBarHeight.calculate(canvasHeight, uniquePersons.length);

    return {
      unitWidth: dynamicUnitWidth,
      personColumnWidth: dynamicPersonColumnWidth,
      barHeight: dynamicBarHeight,
      timeScaleHeight: breakpointConfig.timeScaleHeight,
      breakpoint,
    };
  }

  /**
   * 调整大小变化后的滚动位置
   */
  private adjustScrollPositionAfterResize() {
    const canvasWidth = this.zr.getWidth();
    const canvasHeight = this.zr.getHeight();
    const { totalDays } = this.getTimeConfig();
    const responsiveConfig = this.getResponsiveConfig();

    // 重新计算最大滚动范围
    const maxScrollX = Math.max(0, totalDays * responsiveConfig.unitWidth - canvasWidth + responsiveConfig.personColumnWidth);
    const uniquePersons = getUniquePersons(this.schedules);
    const contentHeight = uniquePersons.length * (responsiveConfig.barHeight + barMargin);
    const maxScrollY = Math.max(0, contentHeight - canvasHeight);

    // 调整滚动位置，确保不超出新的边界
    this.scrollState.lastScrollX = Math.max(0, Math.min(this.scrollState.lastScrollX, maxScrollX));
    this.scrollState.lastScrollY = Math.max(0, Math.min(this.scrollState.lastScrollY, maxScrollY));
  }

  /**
   * 初始化store监听
   */
  initStoreWatcher() {
    this.scheduleStore = useScheduleStore();

    // 监听排班数据变化
    this.unwatchSchedules = watch(
      () => this.scheduleStore.schedules,
      newSchedules => {
        this.schedules = newSchedules;
        // 自动重绘
        this.draw(true, this.scrollState.lastScrollX, this.scrollState.lastScrollY);
      },
      { deep: true },
    );
  }

  /**
   * 清理监听器
   */
  destroy() {
    if (this.unwatchSchedules) {
      this.unwatchSchedules();
      this.unwatchSchedules = null;
    }
    if (this.resizeObserver) {
      this.resizeObserver.disconnect();
      this.resizeObserver = null;
    }
    if (this.resizeTimeout) {
      clearTimeout(this.resizeTimeout);
      this.resizeTimeout = null;
    }
    // 清理甘特表格组件
    this.ganttTable = null;
  }

  /**
   * 找到最后一个排班
   */
  findLastShift(): Shift | null {
    let lastShift: Shift | null = null;
    let maxEnd = -1;

    this.schedules.forEach(schedule => {
      schedule.shifts.forEach(shift => {
        const end = shift.start + shift.duration;
        if (end > maxEnd) {
          maxEnd = end;
          lastShift = shift;
        }
      });
    });

    return lastShift;
  }

  /**
   * 行重排序处理
   * @param fromIndex 起始索引
   * @param toIndex 目标索引
   */
  handleRowReorder = (fromIndex: number, toIndex: number) => {
    if (fromIndex === toIndex) {
      return;
    }

    // 使用store的方法进行重排序
    if (this.scheduleStore) {
      this.scheduleStore.reorderSchedules(fromIndex, toIndex);
    } else {
      // 兼容旧的方式
      const newSchedules = [...this.schedules];
      const [movedItem] = newSchedules.splice(fromIndex, 1);
      newSchedules.splice(toIndex, 0, movedItem);
      this.schedules = newSchedules;
      this.draw(true, this.scrollState.lastScrollX, this.scrollState.lastScrollY);
    }
  };

  /**
   * 绘制排班表
   * @param clear 是否清空
   * @param scrollX 滚动X
   * @param scrollY 滚动Y
   */
  draw(clear = false, scrollX = this.scrollState.lastScrollX, scrollY = 0) {
    const isFirst = this.isFirstFlag;
    if (this.isFirstFlag) {
      this.isFirstFlag = false;
    }

    // 更新滚动状态
    this.scrollState.lastScrollX = scrollX;
    this.scrollState.lastScrollY = scrollY;

    // 计算图表起始位置
    const chartState = this.calculateChartState(scrollX, scrollY);

    // 清空画布
    clear && this.zr.clear();

    // 更新甘特表格组件
    if (this.ganttTable) {
      this.ganttTable.update(this.schedules, chartState);
      this.ganttTable.render();
    }

    // 如果屏幕里没有排班条，调整到第一个
    this.adjustScrollIfNoSchedules(isFirst, 0, chartState);
  }

  /**
   * 计算图表状态
   * @param {number} scrollX 滚动X
   * @param {number} scrollY 滚动Y
   * @returns {ChartState} 图表状态
   */
  calculateChartState(scrollX: number, scrollY: number): ChartState {
    const canvasWidth = this.zr.getWidth();
    const canvasHeight = this.zr.getHeight();
    const responsiveConfig = this.getResponsiveConfig();

    // 限制滚动范围在时间范围内
    // 最大滚动距离 = 总天数 * 单位宽度 - 画布宽度 + 人员列宽度
    const { totalDays } = this.getTimeConfig();
    const maxScrollX = Math.max(0, totalDays * responsiveConfig.unitWidth - canvasWidth + responsiveConfig.personColumnWidth);
    const limitedScrollX = Math.max(0, Math.min(scrollX, maxScrollX));

    // 计算图表起始位置
    const chartStartX = responsiveConfig.personColumnWidth + 1 - limitedScrollX;
    const chartStartY = Math.max(responsiveConfig.timeScaleHeight, responsiveConfig.timeScaleHeight) - scrollY;

    // 计算时间轴宽度
    const timeScaleUnits = Math.ceil(canvasWidth / responsiveConfig.unitWidth);

    return {
      chartStartX,
      chartStartY,
      canvasWidth,
      canvasHeight,
      timeScaleUnits,
      lastScrollX: limitedScrollX,
      lastScrollY: scrollY,
      // 添加响应式配置到图表状态
      responsiveConfig,
    };
  }

  /**
   * 将排班数据转换为任务格式（用于网格线等兼容性功能）
   * @returns {Task[]} 转换后的任务数组
   */
  getSchedulesAsTasksForGrid(): Task[] {
    const tasks: Task[] = [];
    this.schedules.forEach(schedule => {
      schedule.shifts.forEach(shift => {
        tasks.push({
          name: shift.name,
          start: shift.start,
          duration: shift.duration,
          resource: schedule.person.name,
          fillColor: shift.fillColor,
        });
      });
    });
    return tasks;
  }

  /**
   * 如果没有排班条，调整滚动位置到第一个排班
   * @param {boolean} isFirst 是否首次绘制
   * @param {number} drawShiftCount 绘制的排班条数量
   * @param {object} chartState 图表状态对象
   */
  adjustScrollIfNoSchedules(isFirst: boolean, drawShiftCount: number, chartState: ChartState) {
    if (isFirst && drawShiftCount === 0) {
      // 找到第一个排班
      let firstShift: Shift | null = null;
      for (const schedule of this.schedules) {
        if (schedule.shifts.length > 0) {
          firstShift = schedule.shifts[0];
          break;
        }
      }

      if (firstShift) {
        const boundingLeft = Math.floor(chartState.lastScrollX / chartState.responsiveConfig.unitWidth);
        this.scrollState.lastScrollX += (firstShift.start - boundingLeft - 1) * chartState.responsiveConfig.unitWidth;

        // 避免无限递归，直接重新计算并绘制
        const newChartState = this.calculateChartState(this.scrollState.lastScrollX, 0);
        this.zr.clear();

        // 使用甘特表格组件重新渲染
        if (this.ganttTable) {
          this.ganttTable.update(this.schedules, newChartState);
          this.ganttTable.render();
        }
      }
    }
  }

  /**
   * 设置当前操作组
   * @param {object} group 操作组
   */
  setCurrentGroup(group: any) {
    this.currentGroup = group;
    if (this.ganttTable) {
      this.ganttTable.setCurrentGroup(group);
    }
  }

  /**
   * 获取排班数据
   * @returns {PersonSchedule[]} 排班数据
   */
  getSchedules(): PersonSchedule[] {
    return this.schedules;
  }

  /**
   * 更新排班数据
   * @param {PersonSchedule[]} schedules 新的排班数据
   */
  updateSchedules(schedules: PersonSchedule[]) {
    this.schedules = schedules;
  }

  /**
   * 获取store实例
   */
  getScheduleStore() {
    return this.scheduleStore;
  }
}
